﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImportBankDataViewModel.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the <seealso cref="ImportBankDataViewModel" /> type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Client.Modules.Core.Management.ViewModel
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.Contracts;
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;

    using Hisaab.Business.Interfaces;
    using Hisaab.Client.Common;
    using Hisaab.Client.Common.BaseClasses;
    using Hisaab.Client.Common.Services;
    using Hisaab.Client.Model;
    using Hisaab.Client.Modules.Core.Properties;
    using Hisaab.Common;

    using Microsoft.Practices.Prism.Commands;
    using Microsoft.Practices.Prism.Regions;
    using Microsoft.Practices.ServiceLocation;

    using Transaction = Hisaab.Business.Entities.Transaction;

    /// <summary>
    /// Defines the <seealso cref="ImportBankDataViewModel"/> type.
    /// </summary>
    public class ImportBankDataViewModel : WindowViewModel, INavigationAware
    {
        #region Data Member

        /// <summary>
        /// Member variable _dataManager
        /// </summary>
        private readonly IDataManager _dataManager;

        /// <summary>
        /// Account object
        /// </summary>
        private readonly ITransactionManager _transactionManager;

        /// <summary>
        /// Account manager
        /// </summary>
        private readonly IAccountManager _accountManager;

        /// <summary>
        /// Tag Manager
        /// </summary>
        private readonly ITagManager _tagManager;

        /// <summary>
        /// The Session Manager
        /// </summary>
        private readonly ISession _session;

        /// <summary>
        /// Member variable _transactions
        /// </summary>
        private ObservableCollection<ImportTransaction> _transactions;

        /// <summary>
        /// Member variable _selectAll
        /// </summary>
        private bool _selectAll;

        /// <summary>
        /// Member variable _selectedBank
        /// </summary>
        private Banks _selectedBank;

        /// <summary>
        /// Transaction types
        /// </summary>
        private ObservableCollection<KeyValuePair<TransactionTypes, string>> _transactionTypes;

        /// <summary>
        /// Accounts list
        /// </summary>
        private ObservableCollection<Account> _accounts;

        /// <summary>
        /// Member variable _saveCommand
        /// </summary>
        private ICommand _saveCommand;

        /// <summary>
        /// Member field _tagTypes
        /// </summary>
        private ObservableCollection<Tag> _tagTypes;

        #endregion Data Member

        #region Constructors and initializers

        /// <summary>
        /// Initializes a new instance of the <see cref="ImportBankDataViewModel"/> class.
        /// </summary>
        public ImportBankDataViewModel()
            : this(
                ServiceLocator.Current.GetInstance<IDataManager>(),
                ServiceLocator.Current.GetInstance<ITransactionManager>(),
                ServiceLocator.Current.GetInstance<IAccountManager>(),
                ServiceLocator.Current.GetInstance<ITagManager>(),
                ServiceLocator.Current.GetInstance<ISession>())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ImportBankDataViewModel"/> class.
        /// </summary>
        /// <param name="dataManager">The data manager.</param>
        /// <param name="transactionManager">The transaction manager.</param>
        /// <param name="accountManager">The account manager.</param>
        /// <param name="tagManager">The tag manager.</param>
        /// <param name="session">The session.</param>
        public ImportBankDataViewModel(
            IDataManager dataManager,
            ITransactionManager transactionManager,
            IAccountManager accountManager,
            ITagManager tagManager,
            ISession session)
        {
            Contract.Requires<ArgumentNullException>(dataManager != null);
            Contract.Requires<ArgumentNullException>(transactionManager != null);
            Contract.Requires<ArgumentNullException>(accountManager != null);
            Contract.Requires<ArgumentNullException>(tagManager != null);
            Contract.Requires<ArgumentNullException>(session != null);

            _dataManager = dataManager;
            _transactionManager = transactionManager;
            _accountManager = accountManager;
            _tagManager = tagManager;
            _session = session;

            Title = "Import Bank Data";
            Icon = new BitmapImage(new Uri("pack://application:,,,/Hisaab.Client.Common;component/Resources/Images/16/TransactionAdd.png"));
            ResizeMode = ResizeMode.CanResizeWithGrip;
        }

        #endregion Constructors and initializers

        #region Properties

        /// <summary>
        /// Gets or sets the transactions.
        /// </summary>
        /// <value>
        /// The transactions.
        /// </value>
        public ObservableCollection<ImportTransaction> Transactions
        {
            get
            {
                return _transactions;
            }

            set
            {
                RaisePropertyChangingEvent("Transactions");
                _transactions = value;
                RaisePropertyChangedEvent("Transactions");
            }
        }

        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>
        /// The name of the file.
        /// </value>
        public string FileName { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether [select all].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [select all]; otherwise, <c>false</c>.
        /// </value>
        public bool SelectAll
        {
            get
            {
                return _selectAll;
            }

            set
            {
                RaisePropertyChangingEvent("SelectAll");
                _selectAll = value;
                RaisePropertyChangedEvent("SelectAll");

                foreach (var transaction in Transactions)
                {
                    transaction.Selected = true;
                }
            }
        }

        /// <summary>
        /// Gets or sets the selected bank.
        /// </summary>
        /// <value>
        /// The selected bank.
        /// </value>
        public Banks SelectedBank
        {
            get
            {
                return _selectedBank;
            }

            set
            {
                RaisePropertyChangingEvent("SelectedBank");
                _selectedBank = value;
                RaisePropertyChangedEvent("SelectedBank");
            }
        }

        /// <summary>
        /// Gets the Account Types.
        /// </summary>
        /// <value>
        /// The transaction types.
        /// </value>
        public ObservableCollection<KeyValuePair<TransactionTypes, string>> TransactionTypes
        {
            get
            {
                if (_transactionTypes == null)
                {
                    LoadTransactionTypes();
                }

                return _transactionTypes;
            }

            private set
            {
                RaisePropertyChangingEvent("TransactionTypes");
                _transactionTypes = value;
                RaisePropertyChangedEvent("TransactionTypes");
            }
        }

        /// <summary>
        /// Gets the tag types.
        /// </summary>
        /// <value>The tag types.</value>
        public ObservableCollection<Tag> TagTypes
        {
            get
            {
                if (this._tagTypes == null)
                {
                    this._tagTypes = new ObservableCollection<Tag>(_tagManager.List().Select(x => x.Map<Business.Entities.Tag, Tag>()));
                }

                return this._tagTypes;
            }
        }

        /// <summary>
        /// Gets the Account Types.
        /// </summary>
        public ObservableCollection<Account> Accounts
        {
            get
            {
                if (_accounts == null)
                {
                    _accounts = new ObservableCollection<Account>(
                        _accountManager
                            .List(new Business.Entities.Account { UserId = _session.LoggedUser })
                            .OrderBy(x => x.Name)
                            .Select(x => x.Map<Business.Entities.Account, Account>()));
                }

                return _accounts;
            }
        }

        /// <summary>
        /// Gets the save command.
        /// </summary>
        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new DelegateCommand(Save, CanSave);
                }

                return _saveCommand;
            }
        }

        #endregion Properties

        #region Public Methods

        /// <summary>
        /// Called when [import].
        /// </summary>
        /// <returns>Import transaction list</returns>
        public ObservableCollection<ImportTransaction> LoadTransactions()
        {
            try
            {
                var transactions =
                    _dataManager.ImportBankData(FileName, SelectedBank).Select(
                        x => x.Map<Transaction, ImportTransaction>());
                return new ObservableCollection<ImportTransaction>(transactions);
            }
            catch (Exception ex)
            {
                ServiceLocator.Current.GetInstance<IMessageBoxService>().Show(
                    string.Format(Resources.ErrorImportData, ex.Message),
                    Resources.ApplicationName,
                    MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);

                CloseView();
                return new ObservableCollection<ImportTransaction>();
            }
        }

        /// <summary>
        /// Saves the account.
        /// </summary>
        public void Save()
        {
            var remainingTransactions = new List<ImportTransaction>();
            var hasError = false;
            foreach (var transaction in Transactions)
            {
                if (transaction.Selected)
                {
                    try
                    {
                        _transactionManager.Add(transaction.Map<ImportTransaction, Transaction>());
                    }
                    catch
                    {
                        remainingTransactions.Add(transaction);
                        hasError = true;
                    }
                }
            }

            if (hasError)
            {
                ServiceLocator.Current.GetInstance<IMessageBoxService>()
                    .Show(Resources.MessageErrorSavingBulkTransactions, Resources.ApplicationName, MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
            else
            {
                CloseView();
            }

            Transactions = new ObservableCollection<ImportTransaction>(remainingTransactions);
        }

        /// <summary>
        /// Determines whether this instance [can save account] the specified obj.
        /// </summary>
        /// <returns>
        /// True if this instance can save account the specified obj; otherwise, false.
        /// </returns>
        public bool CanSave()
        {
            return true;
        }

        /// <summary>
        /// Closes the view.
        /// </summary>
        public override void CloseView()
        {
            var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
            var region = regionManager.Regions[Regions.SecondaryRegion];
            var view = region.GetView(ManagementModule.ImportBankData);
            if (view != null)
            {
                region.Remove(view);
            }
        }

        #endregion Public Methods

        #region INavigationAware Methods

        /// <summary>
        /// Called when [navigated to].
        /// </summary>
        /// <param name="navigationContext">The navigation context.</param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            if (navigationContext.Parameters["ID"] != null)
            {
                SelectedBank = (Banks)int.Parse(navigationContext.Parameters["ID"]);
            }

            if (navigationContext.Parameters["Source"] != null)
            {
                FileName = navigationContext.Parameters["Source"];
            }

            Transactions = LoadTransactions();
        }

        /// <summary>
        /// Determines whether [is navigation target] [the specified navigation context].
        /// </summary>
        /// <param name="navigationContext">The navigation context.</param>
        /// <returns>
        ///   <c>true</c> if [is navigation target] [the specified navigation context]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return false;
        }

        /// <summary>
        /// Called when [navigated from].
        /// </summary>
        /// <param name="navigationContext">The navigation context.</param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
        }

        #endregion INavigationAware Methods

        #region Private Methods

        /// <summary>
        /// Loads the transaction types.
        /// </summary>
        private void LoadTransactionTypes()
        {
            var types = new List<KeyValuePair<TransactionTypes, string>>
                {
                    new KeyValuePair<TransactionTypes, string>(Model.TransactionTypes.Expanse, "Expanse"),
                    new KeyValuePair<TransactionTypes, string>(Model.TransactionTypes.Income, "Income")
                };

            TransactionTypes = new ObservableCollection<KeyValuePair<TransactionTypes, string>>(types);
        }

        #endregion Private Methods
    }
}